﻿/*
** Xin YUAN, 2021, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////
#ifndef __CTL_IMAGE_DATA_H__
#define __CTL_IMAGE_DATA_H__
////////////////////////////////////////////////////////////////////////////////

#ifndef __CTL_MDA_H__
	#error data.h requires mda.h to be included first.
#endif

/*
data & algorithms for image processing
*/

////////////////////////////////////////////////////////////////////////////////
namespace CTL {
////////////////////////////////////////////////////////////////////////////////

// Pixel types

#pragma pack(push, 1)

struct GrayPixel
{
	uint8_t g;
};
struct Gray2Pixel
{
	uint8_t g;
	uint8_t a;
};
struct ColorPixel
{
	uint8_t r;
	uint8_t g;
	uint8_t b;
};
struct Color2Pixel
{
	uint8_t r;
	uint8_t g;
	uint8_t b;
	uint8_t a;
};

#pragma pack(pop)

// GrayData
typedef MdArray<GrayPixel, 2>  GrayData;
// Gray2Data
typedef MdArray<Gray2Pixel, 2>  Gray2Data;
// ColorData
typedef MdArray<ColorPixel, 2>  ColorData;
// Color2Data
typedef MdArray<Color2Pixel, 2>  Color2Data;

//tools

// T : float, double
template <typename T>
inline T ToGray(T r, T g, T b) noexcept
{
	return (T)(0.299 * r + 0.587 * g + 0.114 * b);
}
template <>
inline uint8_t ToGray<uint8_t>(uint8_t r, uint8_t g, uint8_t b) noexcept
{
	return (uint8_t)((299 * (int32_t)r + 587 * (int32_t)g + 114 * (int32_t)b + 500) / 1000);
}

// ColorData->GrayData
template <class TColorData, class TGrayData>
inline void ColorDataToGrayData(const TColorData& cData, TGrayData& gData)
{
	gData.Free();
	if( cData.IsNull() )
		return ;
	//size
	DimInfoT<uintptr_t, 2> dimExtras;
	dimExtras[0] = dimExtras[1] = 0;
	gData.SetSize(cData.GetSize(), dimExtras);  //may throw
	//loop
	MdaView<2> view;
	auto& dimStarts(view.GetStarts());
	auto& dimSteps(view.GetSteps());
	auto& dimEnds(view.GetEnds());
	dimStarts[0] = dimStarts[1] = 0;
	dimSteps[0] = dimSteps[1] = 1;
	dimEnds = cData.GetSize();
	typename TColorData::Iterator iterSrc;
	typename TGrayData::Iterator iterDest;
	cData.GetIterator(view, iterSrc);
	gData.GetIterator(view, iterDest);
	for ( ; !iterSrc.IsEnd(); iterSrc.ToNext(), iterDest.ToNext() ) {
		assert( !iterDest.IsEnd() );
		const auto& srcPixel(iterSrc.V());
		iterDest.V().g = ToGray(srcPixel.r, srcPixel.g, srcPixel.b);
	}
}

//Functors

template <class TGrayPixel>
class InvertFunctor
{
public:
	void operator()(TGrayPixel& v) const noexcept
	{
		v.g = 255 - v.g;
	}
};

template <class TGrayPixel>
class BooleanInvertFunctor
{
public:
	void operator()(TGrayPixel& v) const noexcept
	{
		v.g = (v.g != 0) ? 0 : 255;
	}
};

template <class TGrayPixel>
class BinaryFunctor
{
public:
	explicit BinaryFunctor(uint8_t t = 0) noexcept : m_threshold(t)
	{
	}

	void operator()(TGrayPixel& v) const noexcept
	{
		v.g = (v.g >= m_threshold) ? 255 : 0;
	}

private:
	uint8_t  m_threshold;
};

//WindowContrast

#pragma pack(push, 1)

// WindowContrast
/*! \brief A structure for window contrast.

A structure for window contrast.
*/
struct WindowContrast
{
	int center;   //!< Window center.
	int width;    //!< Window width.

	/*! \brief Constructor.

	Constructor.
	\param ic [in] A value of Window Center.
	\param iw [in] A value of Window Width.
	*/
	explicit WindowContrast(int ic = 0, int iw = 1) throw() : center(ic), width(iw)
	{
	}
	/*! \brief Get low and high limits.

	Get low and high limits.
	\param iLow, iHigh [out] Receive the low and high limits.
	*/
	void GetLowHigh(int& iLow, int& iHigh) const throw()
	{
		iLow  = center - width / 2;
		iHigh = iLow + width - 1;
	}
	/*! \brief Set window center and width.

	Set window center and width.
	\param ic [in] A value of Window Center.
	\param iw [in] A value of Window Width.
	*/
	void Set(int ic, int iw) throw()
	{
		assert( iw > 0 );
		center = ic;
		width  = iw;
	}
	/*! \brief Set low and high limits.

	Set low and high limits.
	\param iLow [in] A value of low limit.
	\param iHigh [in] A value of high limit.
	*/
	void SetLowHigh(int iLow, int iHigh) throw()
	{
		assert( iLow <= iHigh );
		width  = iHigh - iLow + 1;
		center = iLow + width / 2;
	}
};

#pragma pack(pop)

template <typename T, class TCompareTrait = DefaultCompareTrait<T>>
class RescaleWindowContrastFunctor
{
public:
	RescaleWindowContrastFunctor(const T& low, const T& high) noexcept
				: m_low(low), m_high(high)
	{
	}
	uint8_t operator()(const T& v) const noexcept
	{
		double d = TCompareTrait::IsEQ(m_low, m_high)
				? (double)v - (double)m_low
				: ((double)v - (double)m_low) / ((double)m_high - (double)m_low) * 255.0 + 0.5
				;
		return (d < 0.0) ? 0 : (d > 255.0 ? 255 : (uint8_t)d);
	}

private:
	const T& m_low;
	const T& m_high;
};

////////////////////////////////////////////////////////////////////////////////
}
////////////////////////////////////////////////////////////////////////////////
#endif
////////////////////////////////////////////////////////////////////////////////
